package com.grace.cms.general.interceptor;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import com.alibaba.fastjson2.JSONObject;
import com.grace.common.core.domain.AjaxResult;
import com.grace.common.utils.ServletUtils;
import com.grace.cms.common.domain.entity.CmsTheme;
import com.grace.cms.common.enums.ThemeEnabledEnums;
import com.grace.cms.general.taglib.WebTag;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

/**
 * 主题拦截器
 * 负责拦截请求，验证主题是否存在及状态，控制访问权限
 */
@Component
public class ThemeInterceptor implements HandlerInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(ThemeInterceptor.class);

    @Autowired
    private WebTag webTag;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws ServletException, IOException {
        try {
            // 直接处理favicon.ico请求，读取并返回静态资源
            if (request.getRequestURI().endsWith("/favicon.ico") || request.getRequestURI().equals("/favicon.ico")) {
                // 设置响应类型
                response.setContentType("image/x-icon");
                // 读取静态资源
                try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("static/favicon.ico")) {
                    if (inputStream != null) {
                        // 写入响应
                        IOUtils.copy(inputStream, response.getOutputStream());
                        response.flushBuffer();
                        return false; // 返回false表示请求已处理完成
                    }
                }
            }
            
            String themeName = extractThemeName(request);
            if (themeName == null) {
                logger.warn("无法从请求URL中提取主题名称: {}", request.getRequestURI());
                forwardToDefaultPage(request, response, "/templates/default/pages/web/absent.html", "", "无效的请求路径");
                return false;
            }

            logger.debug("处理主题请求: {}", themeName);
            CmsTheme cmsTheme = webTag.selectCmsThemeByThemeName(themeName);
            if (cmsTheme == null) {
                logger.warn("主题不存在: {}", themeName);
                forwardToDefaultPage(request, response, "/templates/default/pages/web/absent.html", themeName,
                        "请求不允许访问");
                return false;
            }

            int status = cmsTheme.getThemeEnabled();
            logger.debug("主题 {} 状态: {}", themeName, status);

            if (status == ThemeEnabledEnums.CLOSE.ordinal()) {
                logger.info("主题 {} 已关闭", themeName);
                forwardToDefaultPage(request, response, "/templates/default/pages/web/close.html", themeName, "站点已关闭");
                return false;
            } else if (status == ThemeEnabledEnums.UPHOLD.ordinal()) {
                logger.info("主题 {} 维护中", themeName);
                forwardToDefaultPage(request, response, "/templates/default/pages/web/uphold.html", themeName, "站点维护中");
                return false;
            }

            // 主题正常，允许请求继续
            return true;
        } catch (Exception e) {
            logger.error("主题拦截器处理异常", e);
            forwardToDefaultPage(request, response, "/templates/default/pages/web/absent.html", "", "服务器内部错误");
            return false;
        }
    }

    /**
     * 从请求中提取主题名称
     * 
     * @param request HTTP请求
     * @return 主题名称，如果无法提取则返回null
     */
    private String extractThemeName(HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        String contextPath = request.getContextPath();
        String relativePath = requestURI.substring(contextPath.length());

        // 分割路径并过滤空字符串
        String[] pathSegments = Arrays.stream(relativePath.split("/"))
                .filter(segment -> !segment.isEmpty())
                .toArray(String[]::new);

        // 路径格式应为 /contextPath/themeName/...
        return pathSegments.length > 0 ? pathSegments[0] : null;
    }

    /**
     * 转发到默认页面
     * 
     * @param request      HTTP请求
     * @param response     HTTP响应
     * @param templatePath 模板路径
     * @param themeName    主题名称
     * @param errorMsg     错误消息
     */
    private void forwardToDefaultPage(HttpServletRequest request, HttpServletResponse response,
            String templatePath, String themeName, String errorMsg) {
        try {
            response.setContentType("text/html;charset=UTF-8");

            if (ServletUtils.isAjaxRequest(request)) {
                response.getWriter().write(JSONObject.toJSONString(AjaxResult.error(errorMsg)));
            } else {
                String html = readTemplate(templatePath);
                if (html != null) {
                    html = html.replace("${message}", errorMsg)
                            .replace("${themeName}", themeName);
                    response.getWriter().write(html);
                } else {
                    response.getWriter().write("<html><body><h1>" + errorMsg + "</h1></body></html>");
                }
            }
            response.getWriter().flush();
        } catch (Exception e) {
            logger.error("写入错误页面失败", e);
        }
    }

    /**
     * 读取模板文件内容
     * 
     * @param path 模板路径
     * @return 模板内容，如果读取失败则返回null
     */
    private String readTemplate(String path) {
        try (InputStream is = getClass().getResourceAsStream(path)) {
            if (is == null) {
                logger.warn("模板文件不存在: {}", path);
                return null;
            }

            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(is, StandardCharsets.UTF_8))) {
                StringBuilder content = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null) {
                    content.append(line).append("\n");
                }
                return content.toString();
            }
        } catch (IOException e) {
            logger.error("读取模板文件失败: {}", path, e);
            return null;
        }
    }
}
